package snowflake;


import java.util.Comparator;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CountDownLatch;

public class SnowflakeTest {
    // Fri May 19 12:58:09 CST 2023
    private long BASE_TIME = 1684472289975L;

    private int SEQUENCE_BIT = 12;

    private int SEQUENCE_MASK = -1 ^ (-1 << SEQUENCE_BIT);

    private static int WORKER_BIT = 5;

    private int WORKER_MASK = -1 ^ (-1 << WORKER_BIT);

    private int DATACENTER_BIT = 5;

    private int DATACENTER_MASK = -1 ^ (-1 << DATACENTER_BIT);
    // 机器id平移位数
    private int WORKER_SHIFT = SEQUENCE_BIT;
    // 数据中心id平移位数
    private int DATACENTER_SHIFT = WORKER_SHIFT + WORKER_BIT;
    // 时间平移位数
    private int TIMESTAMP_SHIFT = DATACENTER_SHIFT + DATACENTER_BIT;

    // 机器id取值
    private int workerIdValue;

    // 数据中心id取值
    private int datacenterIdValue;

    private long lastTimestamp;

    private int sequenceId;

    private int workerId;

    private int datacenterId;

    public SnowflakeTest(int workerId, int datacenterId) {
        // 校验机器id和数据中心id
        if(workerId > WORKER_MASK) {
            throw new RuntimeException("workerId: " + workerId + " greater than " + WORKER_MASK);
        }
        if(workerId > DATACENTER_MASK) {
            throw new RuntimeException("datacenterId: " + datacenterId + " greater than " + DATACENTER_MASK);
        }
        this.workerId = workerId;
        this.datacenterId = datacenterId;
        this.workerIdValue = workerId << WORKER_SHIFT;
        this.datacenterIdValue = datacenterId << DATACENTER_SHIFT;
    }

    // key: machine address, value: timestamp
//    private static Map<String, Long> map = new HashMap<>();

    public static void main(String[] args) {
        List<Long> list = new Vector<>();
        CountDownLatch latch = new CountDownLatch(10);
        SnowflakeTest test = new SnowflakeTest(0, 0);
        for(int i=0; i < 10; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try{
                        long result = test.nextId();
                        list.add(result);
                    } finally {
                        latch.countDown();
                    }
                }
            }).start();
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(list);
        list.sort(new Comparator<Long>() {
            @Override
            public int compare(Long o1, Long o2) {
                return o1 <= o2 ? -1 : 1;
            }
        });
        System.out.println(list);
    }

    /**
     * 1. 加锁；
     * 2. 时间是否回退的判断；
     * 3. 同一个机器id，同一个时间的判断（sequenceId是否继续递增的判断）；
     * @return
     */
    public synchronized long nextId() {
        long currentTime = System.currentTimeMillis();
        if(currentTime < lastTimestamp) {
            throw new RuntimeException("currentTime: " + currentTime + " less than lastTimestamp " + lastTimestamp);
        }
        if(lastTimestamp == currentTime) {
            sequenceId = (sequenceId + 1) & SEQUENCE_MASK;
            if(sequenceId == 0) {
                currentTime = tilNextMillis();
            }
        } else {
            sequenceId = 0;
        }
        // 记录上次的时间戳
        lastTimestamp = currentTime;
        System.out.println(Thread.currentThread().getName() + ", sequenceId: " + sequenceId);
        long res = 0;
        // time value
        long timeMillis = currentTime - BASE_TIME;
        res += timeMillis << TIMESTAMP_SHIFT;
        // datacenter id value
        res += datacenterIdValue;
        // worker id value
        res += workerIdValue;
        // sequence id value
        res += sequenceId;
        return res;
    }

    private long tilNextMillis() {
        long timestamp = System.currentTimeMillis();
        while(timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}
